package com.swlz.servlet;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.swlz.Const;
import com.swlz.R;
import com.swlz.commons.JsonUtil;
import com.swlz.exception.CodeException;
import com.swlz.vo.LoginUser;

import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.ServletUtil;

/**
 * <pre>
 * - 使用反射根据参数action执行不同的方法
 * ClassName : com.swlz.servlet.HttpServletSupport
 * Author : swlz
 * E-Mail : 2233875735@qq.com
 * Date : 2020年7月5日 下午9:07:35
 * Version : 1.0
 * Copyright 2020 swlz.top Inc. All rights reserved. 
 * Warning: this content is only for internal circulation of the company. 
 * It is forbidden to divulge it or use it for other commercial purposes!</pre>
 */
@SuppressWarnings("serial")
public class HttpServletSupport extends HttpServlet {

	protected Logger log = LoggerFactory.getLogger(this.getClass());
	private Class<?> cls = this.getClass();

	private Map<String, Method> methods = new HashMap<String, Method>();

	@Override
	public void init() throws ServletException {
		for (Method m : cls.getMethods()) {
			methods.put(m.getName(), m);
		}
	}

	@Override
	protected final void service(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		// 获取要执行的方法名
		String methodName = request.getParameter("action");
		if (StrUtil.hasBlank(methodName)) {
			methodName = "execute";
		}

		// 获取要执行的方法
		Method method = methods.get(methodName);
		if (method == null) {
			response.sendError(404, "没有找到方法：" + cls.getName() + "." + methodName);
			return;
		}

		// 获取要执行的方法的参数
		Object[] args = new Object[method.getParameterTypes().length];
		for (int i = 0; i < args.length; i++) {
			Class<?> c = method.getParameterTypes()[i];
			if (c == HttpServletRequest.class) {
				args[i] = request;
			} else if (c == HttpServletResponse.class) {
				args[i] = response;
			} else if (c == HttpSession.class) {
				args[i] = request.getSession();
			} else if (c == ServletContext.class) {
				args[i] = getServletContext();
			} else if (c == LoginUser.class) {
				args[i] = Const.getLoginUser(request.getSession());
			} else {
				try {
					args[i] = c.newInstance();
					ServletUtil.fillBean(request, args[i], true);
				} catch (Exception e) {
					log.warn(cls.getName() + "." + methodName + "的参数" + c.getName() + "初始化失败", e);
				}
			}
		}

		// 执行方法
		Object ret = null;
		Throwable ex = null;
		try {
			ret = method.invoke(this, args);
		} catch (Exception e) {
			ex = e.getCause();
		}

		//处理结果
		if (method.getReturnType() == void.class) {//传统的MVC
			if (ex != null) {
				throw new ServletException(ex.getMessage(), ex);
			}
		} else if (method.getReturnType() == String.class) {//传统的MVC
			if(ex != null) {
				throw new ServletException(ex.getMessage(), ex);
			}else {//如果返回字符串，并且正常运行，则进行视图调整
				String toURL = (String) ret;
				if(StrUtil.hasBlank(toURL)){
					return;
				}
				if (toURL.startsWith("redirect:")) {
					response.sendRedirect(request.getContextPath() +"/"+ toURL.substring(9));
				} else  if(toURL.startsWith("forward:")){
					request.getRequestDispatcher(toURL.substring(8)).forward(request, response);
				}else{
					String template = request.getParameter("template");
					if(StrUtil.hasBlank(template)){
						request.getRequestDispatcher("/"+toURL+".jsp").forward(request, response);
					}else{
						request.getRequestDispatcher("/"+toURL+"-"+template+".jsp").forward(request, response);
					}
				}
			}
			
		} else {//输出JSON格式
			if(ex == null) {
				JsonUtil.out(ret, response);
			}else {
				log.warn(ex.getMessage(),ex);
				if(ex instanceof CodeException) {
					CodeException e = (CodeException)ex;
					JsonUtil.out(R.msg(e.getCode(), e.getMessage()), response);
				}else {
					JsonUtil.out(R.error(ex.getMessage()), response);
				}
			}
		}

	}

	@Override
	protected final void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
	}

	@Override
	protected final void doDelete(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
	}

	@Override
	protected final void doHead(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

	}

	@Override
	protected final void doOptions(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {

	}

	@Override
	protected final void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

	}

	@Override
	protected final void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

	}

	@Override
	protected final void doTrace(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {

	}
}
